#ifndef __ENVELOPE_MANAGER_H__
#define __ENVELOPE_MANAGER_H__

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include <vector>
#include <utility>
#include "Quadruple.hpp"
#include "Point3D.hpp"

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace SC {

////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////

class MaskInfo;

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/// Envelope manager
class EnvelopeManager {

	public:

		/// Constructor
		EnvelopeManager();

		/// Returns the number of computations (read-only)
		const unsigned long GetNbComputations() const { return this->nb_computations; }

		/// Returns the number of computations
		unsigned long & NbComputations() { return this->nb_computations; }

		/// Returns the surfaces (read-only) [3 pairs of point & colour index pointer, number of computations]
		const std::vector<
			Types::Quadruple<
				std::pair< const Types::Point3D<float> *, const int * >,
				std::pair< const Types::Point3D<float> *, const int * >,
				std::pair< const Types::Point3D<float> *, const int * >,
				unsigned long
			>
		> & GetSurfaces() const { return this->surfaces; }

		/// Returns the surfaces
		std::vector<
			Types::Quadruple<
				std::pair< const Types::Point3D<float> *, const int * >,
				std::pair< const Types::Point3D<float> *, const int * >,
				std::pair< const Types::Point3D<float> *, const int * >,
				unsigned long
			>
		> & Surfaces() { return this->surfaces; }

		/// Returns the number of stacks
		const unsigned int GetNbStacks() const { return this->nb_stacks; }

		/// Sets the number of stacks
		void SetNbStacks(const unsigned int);

		/// Returns the number of slices
		const unsigned int GetNbSlices() const { return this->nb_slices; }

		/// Sets the number of slices
		void SetNbSlices(const unsigned int);

		/// Updates the envelope
		void Update(
			const std::pair< const Types::Point3D<float> *, const int * >,
			const std::pair< const Types::Point3D<float> *, const int * >,
			const std::pair< const Types::Point3D<float> *, const int * >
		);

		/// Draw the envelopes
		void DrawEnvelopes(
			const std::vector<int> &,
			const std::vector<MaskInfo> &,
			const float = 0.f,
			const float = 1.f,
			const float = 1.f
		) const;

		/// Clear the record
		void Clear() {
			this->nb_computations = 0;
			this->surfaces.clear();
		}

	protected:

		/// Amount of recorded computations
		unsigned long nb_computations;

		/// Surfaces points triplet
		std::vector<
			Types::Quadruple<
				std::pair< const Types::Point3D<float> *, const int * >,
				std::pair< const Types::Point3D<float> *, const int * >,
				std::pair< const Types::Point3D<float> *, const int * >,
				unsigned long
			>
		> surfaces;

		/// Number of stacks
		unsigned int nb_stacks;

		/// Number of slices
		unsigned int nb_slices;

		/// Prepares the array of indices
		void set_indices();

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
